iT邦幫忙

2021 iThome 鐵人賽

DAY 2
0
Mobile Development

Jetpack Compose系列 第 4

[Day4] Jetpack Compose: 要如何讓元件和我們來點互動?

  • 分享至 

  • xImage
  •  

知道怎麼構建UI後,我們來學學怎麼跟UI的互動

clickable

最簡單的方式就是新增Modifier.clickable,比如說新增text被點擊事件:

Text(
    text = "123",
    modifier = Modifier.clickable { Log.d("clickable", "click!") }
)

點擊之後就會出現:

D/clickable: click!

那如果搭配昨天的mutableStateOf的使用方式:

val count = remember { mutableStateOf(0) }
Text(
    text = count.value.toString(),
    modifier = Modifier.clickable { count.value += 1 }
)

記得第一行要在composable的範圍裏面,不能宣告成一般kotlin的全域或區域變數,那我們就完成了一個每點一下就會加一的計數器++++++

pointerInput

如果想要實現原本的onTouchEvent能完成的事件偵測,那可以使用Modifier.pointerInput來完成,裡面則是依照需求放入PointerInputScope.detectTapGestures或 PointerInputScope.detectDragGestures:

點擊偵測:

Modifier.pointerInput(Unit) {
    detectTapGestures(
        onPress = { /* Called when the gesture starts */ },
        onDoubleTap = { /* Called on Double Tap */ },
        onLongPress = { /* Called on Long Press */ },
        onTap = { /* Called on Tap */ }
    )
}

拖動效果:

suspend fun PointerInputScope.detectDragGestures(
    onDragStart: (Offset) -> Unit = { },
    onDragEnd: () -> Unit = { },
    onDragCancel: () -> Unit = { },
    onDrag: (PointerInputChange, Offset) -> Unit
): Unit

或是我們可以使用底下的code來實現橫向的拖動:

var offsetX by remember { mutableStateOf(0f) }
Text(modifier = Modifier
    .offset {
        IntOffset(offsetX.roundToInt(), 0)
    }
    .draggable(
        orientation = Orientation.Horizontal,
        state = rememberDraggableState(onDelta = { delta ->
            offsetX += delta
        }
        )
    ),
    text = "Drag me!")

offset可以實現元件的偏移位置,因為我們只移動X軸,所以y軸維持0,X軸的位置則是從offsetX.roundToInt()來讀取,然後使用rememberDraggableState來更新拖動的位置。

swiping

有時候會有需要實作功能開關,或者非連續的狀態切換的話,可以使用swiping來達成這個目標,同時我們也可以設定當滑動過半的時候,使用anchors讓要活動的對象直接切換到對應的位:

swipeableState:通过 swipeableState 的设置可以獲得現在元件移動到哪裡
anchors:可以設置在不同狀態時所對應的不偏移量,
orientation:手勢的方向

於是我們時現的方式就來了:

val width = 200.dp
val squareSize = 100.dp

val swipeableState = rememberSwipeableState(0)
val sizePx = with(LocalDensity.current) { squareSize.toPx() }
val anchors = mapOf(0f to 0, sizePx to 1)

Box(
    modifier = Modifier
        .width(width)
        .swipeable(
            state = swipeableState,
            anchors = anchors,
            orientation = Orientation.Horizontal
        )
        .background(Color.LightGray)
) {
    Box(
        Modifier
            .offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
            .size(squareSize)
            .background(Color.DarkGray)
    )
}

with(LocalDensity.current) { 16.dp.toPx() } 可以先當作把dp轉成px的一種方式,然後開關的判斷方式,是利用我們定義的anchors來決定是0還是1,這樣我們定義的box就會利用offset對應到0或者是1的位置。


上一篇
[Day3] Jetpack Compose: 為什麼這個EditText不會動?
系列文
Jetpack Compose4
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
MumiRabbit
iT邦新手 4 級 ‧ 2021-09-09 17:59:26

不好意思,想請問這種方式也可以跟xml一樣即時觀看畫面大概會長怎樣嗎?還是只能燒到手機內

我要留言

立即登入留言